﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Input;

namespace Rifts.Controls
{


	[ContentProperty("Content")]
	[TemplatePartAttribute(Name = "HeaderPart", Type = typeof(TextBlock))]
	[TemplatePartAttribute(Name = "TextPart", Type = typeof(Border))]
	public class LabeledTextBlock : Control
	{
		static LabeledTextBlock()
		{
			DefaultStyleKeyProperty.OverrideMetadata(typeof(LabeledTextBlock), new FrameworkPropertyMetadata(typeof(LabeledTextBlock)));
		}

		public LabeledTextBlock()
		{
			Loaded += LabeledTextBlock_Loaded;
			SizeChanged += LabeledTextBlock_SizeChanged;
			HeaderChanged += LabeledTextBlock_SizeChanged;
			TextWidthChanged += LabeledTextBlock_SizeChanged;

			MouseEnter += AddBorder;
			MouseLeave += RemoveBorder;
			MouseUp += RemoveBorder;
		}

		void LabeledTextBlock_Loaded(object sender, RoutedEventArgs e)
		{
			LabeledTextBlock_SizeChanged(sender, e);
		}

		void RemoveBorder(object sender, MouseEventArgs e)
		{
			VisualStateManager.GoToState(this, "Normal", false);
		}

		void AddBorder(object sender, MouseEventArgs e)
		{
			if(Command!=null && Command.CanExecute(CommandParameter))
				VisualStateManager.GoToState(this, "MouseOver", false);
		}


		void LabeledTextBlock_SizeChanged(object sender, EventArgs e)
		{
			var header = (TextBlock)GetTemplateChild("HeaderPart");
			var border = (Border)GetTemplateChild("TextPart");

			if (border == null)
				return;

			//TextWidth overrides the automatically calculated values
			if (!double.IsNaN(TextWidth))
			{
				border.Width = TextWidth;
				return;
			}

			if (double.IsNaN(Width))
			{
				border.Width = double.NaN;
				return;
			}
			var borderWidth = Width;

			borderWidth -= header.ActualWidth;
			borderWidth -= border.Margin.Left;
			borderWidth -= border.Margin.Right;

			border.Width = Math.Max(0, borderWidth);
		}

		


		#region Text

		public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(LabeledTextBlock), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsMeasure, OnTextChanged));

		private static void OnTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		{
			var control = o as LabeledTextBlock;
			if (control != null)
				control.OnTextChanged((string)e.OldValue, (string)e.NewValue);
		}




		protected virtual void OnTextChanged(string oldValue, string newValue)
		{

		}

		public string Text
		{
			get { return (string)GetValue(TextProperty); }
			set { SetValue(TextProperty, value); }
		}
		#endregion


		#region Header

		public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(LabeledTextBlock), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsMeasure, OnHeaderChanged));

		private static void OnHeaderChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		{
			var var = o as LabeledTextBlock;
			if (var != null)
				var.OnHeaderChanged((string)e.OldValue, (string)e.NewValue);
		}


		public event EventHandler HeaderChanged;

		protected virtual void OnHeaderChanged(string oldValue, string newValue)
		{
			if (HeaderChanged!=null)
				HeaderChanged(this, EventArgs.Empty);
		}

		public string Header
		{
			get { return (string)GetValue(HeaderProperty); }
			set { SetValue(HeaderProperty, value); }
		}

		#endregion


		//#region HeaderAlignment

		///// <summary>
		///// This is used to override the automatically calculated width of the header portion of the control. This is used to vertiacally line up multiple LabeledTextBlocks.
		///// </summary>
		//public TextAlignment HeaderAlignment
		//{
		//    get { return (TextAlignment)GetValue(HeaderAlignmentProperty); }
		//    set { SetValue(HeaderAlignmentProperty, value); }
		//}


		//public static readonly DependencyProperty HeaderAlignmentProperty =
		//    DependencyProperty.RegisterAttached("HeaderAlignment", typeof(TextAlignment), typeof(LabeledTextBlock),
		//    new FrameworkPropertyMetadata(TextAlignment.Center, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.Inherits, OnHeaderAlignmentChanged, CoerceHeaderAlignment));


		//static object CoerceHeaderAlignment(DependencyObject d, object baseValue)
		//{
		//    //This doesn't work, something is missing
		//    if (baseValue == null)
		//        return null;

		//    switch (baseValue.ToString())
		//    {
		//        case "Left": return TextAlignment.Left;
		//        case "Right": return TextAlignment.Right;
		//        case "Center": return TextAlignment.Center;
		//        case "Justify;": return TextAlignment.Justify;
			
		//        default:
		//            throw new ArgumentOutOfRangeException(String.Format("Cannot coerce the value {0} into a TextAlignment", baseValue));
		//    }
		//}

		//public static void SetHeaderAlignment(UIElement element, double value)
		//{
		//    element.SetValue(HeaderAlignmentProperty, value);
		//}

		//public static TextAlignment GetHeaderAlignment(UIElement element)
		//{
		//    return (TextAlignment)element.GetValue(HeaderAlignmentProperty);
		//}


		//private static void OnHeaderAlignmentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		//{
		//    var var = o as LabeledTextBlock;
		//    if (var != null)
		//        var.OnHeaderAlignmentChanged((TextAlignment)e.OldValue, (TextAlignment)e.NewValue);
		//}


		//public event EventHandler HeaderAlignmentChanged;
		//protected virtual void OnHeaderAlignmentChanged(TextAlignment oldValue, TextAlignment newValue)
		//{
		//    if (HeaderAlignmentChanged != null)
		//        HeaderAlignmentChanged(this, EventArgs.Empty);
		//}

		//#endregion

		#region HeaderWidth

		/// <summary>
		/// This is used to override the automatically calculated width of the header portion of the control. This is used to vertiacally line up multiple LabeledTextBlocks.
		/// </summary>
		public double HeaderWidth
		{
			get { return (double)GetValue(HeaderWidthProperty); }
			set { SetValue(HeaderWidthProperty, value); }
		}


		public static readonly DependencyProperty HeaderWidthProperty =
			DependencyProperty.RegisterAttached("HeaderWidth", typeof(double), typeof(LabeledTextBlock),
			new FrameworkPropertyMetadata(Double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.Inherits, OnHeaderWidthChanged));

		public static void SetHeaderWidth(UIElement element, double value)
		{
			element.SetValue(HeaderWidthProperty, value);
		}

		public static double GetHeaderWidth(UIElement element)
		{
			return (double)element.GetValue(HeaderWidthProperty);
		}


		private static void OnHeaderWidthChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		{
			var var = o as LabeledTextBlock;
			if (var != null)
				var.OnHeaderWidthChanged((double)e.OldValue, (double)e.NewValue);
		}


		public event EventHandler HeaderWidthChanged;
		protected virtual void OnHeaderWidthChanged(double oldValue, double newValue)
		{
			if (HeaderWidthChanged != null)
				HeaderWidthChanged(this, EventArgs.Empty);
		}

		#endregion


		#region TextWidth

		/// <summary>
		/// This is used to override the automatically calculated width of the underlined portion of the control.
		/// </summary>
		/// <remarks>Either TextWidth or Width should be set.</remarks>
		public double TextWidth
		{
			get { return (double)GetValue(TextWidthProperty); }
			set { SetValue(TextWidthProperty, value); }
		}


		public static readonly DependencyProperty TextWidthProperty =
			DependencyProperty.RegisterAttached("TextWidth", typeof(double), typeof(LabeledTextBlock),
			new FrameworkPropertyMetadata(Double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.Inherits, OnTextWidthChanged));

		public static void SetTextWidth(UIElement element, double value)
		{
			element.SetValue(TextWidthProperty, value);
		}

		public static double GetTextWidth(UIElement element)
		{
			return (double)element.GetValue(TextWidthProperty);
		}


		private static void OnTextWidthChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		{
			var var = o as LabeledTextBlock;
			if (var != null)
				var.OnTextWidthChanged((double)e.OldValue, (double)e.NewValue);
		}


		public event EventHandler TextWidthChanged;
		protected virtual void OnTextWidthChanged(double oldValue, double newValue)
		{
			if(TextWidthChanged!=null)
				TextWidthChanged(this, EventArgs.Empty);
		}

		#endregion

		#region TextHeight
		public static readonly DependencyProperty TextHeightProperty =
				DependencyProperty.RegisterAttached("TextHeight", typeof(double), typeof(LabeledTextBlock),
					new FrameworkPropertyMetadata(Double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.Inherits, OnTextHeightChanged));


		private static void OnTextHeightChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		{
			var var = o as LabeledTextBlock;
			if (var != null)
				var.OnTextHeightChanged((double)e.OldValue, (double)e.NewValue);
		}

		protected virtual void OnTextHeightChanged(double oldValue, double newValue)
		{
		}

		public double TextHeight
		{
			get { return (double)GetValue(TextHeightProperty); }
			set { SetValue(TextHeightProperty, value); }
		}

		public static void SetTextHeight(UIElement element, double value)
		{
			element.SetValue(TextHeightProperty, value);
		}

		public static double GetTextHeight(UIElement element)
		{
			return (double)element.GetValue(TextHeightProperty);
		}
		#endregion


		#region Orientation

		public static readonly DependencyProperty OrientationProperty = DependencyProperty.RegisterAttached("Orientation", typeof(Orientation), typeof(LabeledTextBlock),
	new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.Inherits, OnOrientationChanged));

		public static void SetOrientation(UIElement element, Orientation value)
		{
			element.SetValue(OrientationProperty, value);
		}

		public static Orientation GetOrientation(UIElement element)
		{
			return (Orientation)element.GetValue(OrientationProperty);
		}





		private static void OnOrientationChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		{
			var control = o as LabeledTextBlock;
			if (control != null)
				control.OnOrientationChanged((Orientation)e.OldValue, (Orientation)e.NewValue);
		}


		protected virtual void OnOrientationChanged(Orientation oldValue, Orientation newValue)
		{

		}

		public Orientation Orientation
		{
			get { return (Orientation)GetValue(OrientationProperty); }
			set { SetValue(OrientationProperty, value); }
		}
		#endregion



		#region HeaderFontSize
		public static readonly DependencyProperty HeaderFontSizeProperty =
				DependencyProperty.RegisterAttached("HeaderFontSize", typeof(double), typeof(LabeledTextBlock),
					new FrameworkPropertyMetadata(Double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.Inherits, OnHeaderFontSizeChanged));


		private static void OnHeaderFontSizeChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		{
			var var = o as LabeledTextBlock;
			if (var != null)
				var.OnHeaderFontSizeChanged((double)e.OldValue, (double)e.NewValue);
		}

		protected virtual void OnHeaderFontSizeChanged(double oldValue, double newValue)
		{
		}

		public double HeaderFontSize
		{
			get { return (double)GetValue(HeaderFontSizeProperty); }
			set { SetValue(HeaderFontSizeProperty, value); }
		}

		public static void SetHeaderFontSize(UIElement element, double value)
		{
			element.SetValue(HeaderFontSizeProperty, value);
		}

		public static double GetHeaderFontSize(UIElement element)
		{
			return (double)element.GetValue(HeaderFontSizeProperty);
		}
		#endregion

		#region Content
		public static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(object), typeof(LabeledTextBlock), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure, OnContentChanged));


		private static void OnContentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		{
			var control = o as LabeledTextBlock;
			if (control != null)
				control.OnContentChanged((object)e.OldValue, (object)e.NewValue);
		}


		protected virtual void OnContentChanged(object oldValue, object newValue)
		{
			
		}

		public object Content
		{
			get { return (object)GetValue(ContentProperty); }
			set { SetValue(ContentProperty, value); }
		}
		#endregion



		#region Command
		public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(LabeledTextBlock), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure, OnCommandChanged));


		private static void OnCommandChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		{
			var control = o as LabeledTextBlock;
			if (control != null)
				control.OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue);
		}


		protected virtual void OnCommandChanged(ICommand oldValue, ICommand newValue)
		{

		}

		public ICommand Command
		{
			get { return (ICommand)GetValue(CommandProperty); }
			set { SetValue(CommandProperty, value); }
		}
		#endregion

		#region CommandParameter
		public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(LabeledTextBlock), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure, OnCommandParameterChanged));


		private static void OnCommandParameterChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
		{
			var control = o as LabeledTextBlock;
			if (control != null)
				control.OnCommandParameterChanged((object)e.OldValue, (object)e.NewValue);
		}


		protected virtual void OnCommandParameterChanged(object oldValue, object newValue)
		{

		}

		public object CommandParameter
		{
			get { return (object)GetValue(CommandParameterProperty); }
			set { SetValue(CommandParameterProperty, value); }
		}
		#endregion
	}
}
